﻿using System;
using System.Collections.Generic;
using LumenLiquid.Debug;
using NHibernate;
using System.Linq;

namespace LumenLiquid.Database
{
    /// <summary>
    /// Generall Operations for Databases
    /// </summary>
    public class DatabaseInteraction
    {
        /// <summary>
        /// Saves an object into the current session
        /// </summary>
        /// <param name="session">The session to use for saving</param>
        /// <param name="o">The object to save</param>
        /// <returns>Whether writing was sucessfully or not</returns>
        public static bool SaveObject(ISession session, object o)
        {
            using (var transaction = session.BeginTransaction())
            {
                try
                {
                    session.SaveOrUpdate(o);

                    transaction.Commit();
                    return true;
                }
                catch (Exception)
                {
                    transaction.Rollback();
                    return false;
                }
            }
        }

        /// <summary>
        /// Saves multiple objects into the given session
        /// </summary>
        /// <param name="session">The session to use for saving</param>
        /// <param name="objects">The objects to save</param>
        /// <returns>Whether saving of all objects was sucessfully or not</returns>
        public static bool SaveObject(ISession session, IEnumerable<object> objects)
        {
            using (var transaction = session.BeginTransaction())
            {
                try
                {
                    foreach (var o in objects)
                    {
                        session.SaveOrUpdate(o);
                    }

                    transaction.Commit();
                    return true;
                }
                catch (Exception)
                {
                    transaction.Rollback();
                    return false;
                }
            }
        }

        public static T ReadObject<T>(ISession session, object id)
        {
            using (var transaction = session.BeginTransaction())
            {
                try
                {
                    return session.Get<T>(id);
                }
                catch (Exception)
                {
                    transaction.Rollback();
                    return default(T);
                }
            }
        }

        public static T ReadObject<T>(IStatelessSession session, object id)
        {
            using (var transaction = session.BeginTransaction())
            {
                try
                {
                    return session.Get<T>(id);
                }
                catch (Exception)
                {
                    transaction.Rollback();
                    return default(T);
                }
            }
        }

        /// <summary>
        /// Reads all objects of a specific type out of the database
        /// </summary>
        /// <typeparam name="T">The type to read from the database</typeparam>
        /// <param name="session">The session to use for reading</param>
        /// <returns>An IEnumerable of <typeparamref name="T"/> containing all objects</returns>
        public static IEnumerable<T> ReadAllObjects<T>(ISession session) where T : class
        {
            using (var transaction = session.BeginTransaction())
            {
                try
                {
                    return session.CreateCriteria<T>().List<T>();
                }
                catch (Exception)
                {
                    transaction.Rollback();
                    return null;
                }
            }
        }

        /// <summary>
        /// Reads all objects of a specific type out of the database
        /// </summary>
        /// <typeparam name="T">The type to read from the database</typeparam>
        /// <param name="session">The statelesssession to use for reading</param>
        /// <param name="predicate">A function which defines whether to load or not to load</param>
        /// <returns>An IEnumerable of <typeparamref name="T"/> containing all objects</returns>
        public static IEnumerable<T> ReadAllObjects<T>(IStatelessSession session, Func<T, bool> predicate) where T : class
        {
            using (var transaction = session.BeginTransaction())
            {
                try
                {
                    return session.CreateCriteria<T>().List<T>().Where(predicate);
                }
                catch (Exception)
                {
                    transaction.Rollback();
                    return null;
                }
            }
        }

        /// <summary>
        /// Reads all objects of a specific type out of the database
        /// </summary>
        /// <typeparam name="T">The type to read from the database</typeparam>
        /// <param name="session">The statelesssession to use for reading</param>
        /// <returns>An IEnumerable of <typeparamref name="T"/> containing all objects</returns>
        public static IEnumerable<T> ReadAllObjects<T>(IStatelessSession session) where T : class
        {
            using (var transaction = session.BeginTransaction())
            {
                try
                {
                    return session.CreateCriteria<T>().List<T>();
                }
                catch (Exception)
                {
                    transaction.Rollback();
                    return null;
                }
            }
        }
    }
}
